﻿/*

@author hyjiacan
@version: 0.0.1
@date 2015-12-23
@site: http://www.hyjiacan.com/jquery-miniform/
@QQGroup 187786345

@=====================
 表单操作
 依赖jquery

 使用说明：
 var form = $('#form').miniform({
    autoValidate: true,
    afterValidate: function(result, detail)
 });
 // 取表单所有输入
 var data = form.getData();
 // 设置表单数据
 form.setData(data);
 // 重置表单
 form.reset();
 //验证表单
 form.validate();
 // 提交表单
 form.submit({
 // 这里和$.ajax配置一致
 // 默认的url取form的action，type取form的method
 });
*/
(function ($) {
    var form = function (selector, option) {
        return new form.prototype.init(selector, option);
    };

    form.prototype = {
        constructor: form,
        init: function (selector, option) {
            var me = this;
            me.option = $.extend({}, option);
            // 表单的DOM上下文
            me.context = $(selector);

            // 绑定事件
            if (me.option.autoValidate) {
                var fields = me.getFields();
                for (var name in fields) {
                    fields[name].forEach(function (item) {
                        item.blur((function (form, name) {
                            form.validate(name);
                        }).bind(item, me, name));
                    });
                }
            }

            return me;
        },
        // 获取所有的输入控件 包括  input select textarea
        // all 为 false 时，只获取指定了name属性的控件，否则获取所有控件 默认为false
        getFields: function (all) {

            var ctrls = {};

            // 相同name控件会被放到数组中

            this.context.find('input, select, textarea').each(function () {
                var name = $.trim($(this).attr('name'));
                if (name == '' && !all) {
                    return;
                }

                if (typeof ctrls[name] === 'undefined') {
                    // 不存在name
                    ctrls[name] = [$(this)];
                } else {
                    // 存在name
                    ctrls[name].push($(this));
                }
            });

            return ctrls;
        },
        // 根据name属性获取控件 返回数组，因为可能存在同name情况
        getField: function (name) {
            return this.getFields()[name];
        },
        // 设置所有有效控件的值，form实例
        // field 是控件的name名称，如果指定了此参数，则只设置name=此值的控件的值为data
        setData: function (data, field) {
            var me = this;
            // 未指定参数，设置表单所有项
            if (typeof field === 'undefined') {
                var fields = this.getFields();
                for (var name in fields) {
                    var val = data[name];
                    if (typeof val === 'undefined') {
                        val = '';
                    }

                    me.setData(val, fields[name]);
                }

                return me;
            }

            // 参数是name名字
            if (typeof field === 'string') {
                field = me.getField(field);
                if (!field.length) {
                    return me;
                }
            }

            if ($.isArray(field)) {
                var tag, type;
                field.forEach(function (item) {
                    item = $(item);
                    tag = item.get(0).tagName.toLowerCase();
                    if (tag == 'input') {
                        type = item.attr('type');
                        // 处理radio
                        if (type == 'radio') {
                            item.attr('checked', item.val() == data);
                        } else if (type == 'checkbox') {
                            // 处理checobox
                            item.attr('checked', data);
                        } else {
                            item.val(data);
                        }
                    } else {
                        item.val(data);
                    }
                });
            }

            return me;
        },
        // 获取所有有效控件的值，返回对象
        // field 是控件的name名称，如果指定了此参数，则只取name=此值的控件的值
        getData: function (field) {
            var me = this;
            // 未指定参数，获取表单所有项
            if (typeof field === 'undefined') {
                var data = {};
                var fields = this.getFields();
                for (var name in fields) {
                    data[name] = me.getData(fields[name]);
                }

                return data;
            }

            // 参数是name名字
            if (typeof field === 'string') {
                field = me.getField(field);
                if (!field || !field.length) {
                    return;
                }
            }
            if ($.isArray(field)) {
                var val, tag, type;

                for (var i = 0; i < field.length; i++) {
                    var item = $(field[i]);
                    tag = item.get(0).tagName.toLowerCase();
                    if (tag == 'input') {
                        type = item.attr('type');
                        // 处理radio
                        if (type == 'radio') {
                            if (item.is(':checked')) {
                                val = item.val();
                                break;
                            }
                        } else if (type == 'checkbox') {
                            // 处理checobox
                            val = item.is(':checked');
                        } else {
                            val = item.val();
                        }
                    } else {
                        val = item.val();
                    }
                }

                return typeof val === 'undefined' ? '' : val;
            }
        },
        // 重置表单
        reset: function () {
            this.context.get(0).reset();
            return this;
        },
        getRule: function (field) {
            var me = this;
            // 未指定参数，获取表单所有项
            if (typeof field === 'undefined') {
                var data = {};
                var fields = this.getFields();
                for (var name in fields) {
                    data[name] = me.getData(fields[name]);
                }

                return data;
            }

            // 参数是name名字
            if (typeof field === 'string') {
                field = me.getField(field);
                if (!field.length) {
                    return;
                }
            }
            if ($.isArray(field)) {
                var rule, temp, msg;
                field.forEach(function (item) {
                    item = $(item);
                    temp = item.attr('data-rule');
                    if (temp) {
                        rule = temp;
                        msg = item.attr('data-fail') || '';
                    }
                });

                var validation = { expr: '', msg: '' };
                switch (rule) {
                    case 'require':
                        // 必填
                        validation.expr = /^.+$/;
                        validation.msg = msg || '不能为空';
                        break;
                    case 'number':
                        // 数字
                        validation.expr = /^[0-9]+$/;
                        validation.msg = msg || '请输入数字';
                        break;
                    case 'alpha':
                        // 字母
                        validation.expr = /^[a-zA-Z]+$/;
                        validation.msg = msg || '请输入字母';
                        break;
                    case 'email':
                        // 邮箱
                        validation.expr = /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/;
                        validation.msg = msg || '请输入有效的邮箱';
                        break;
                    case 'site':
                        // 网址
                        validation.expr = /^[0-9a-z]+(\.[0-9a-z\-_])*\.[\w]+$/i;
                        validation.msg = msg || '请输入有效的网址';
                        break;
                    case '':
                        validation = false;
                        break;
                    default:
                        // 如果验证以regex:开头，表示需要使用正则验证
                        if (rule && rule.indexOf('regex:') == 0) {
                            validation.expr = new RegExp(rule.replace('regex:', ''));
                            validation.msg = msg || '验证失败';
                        } else {
                            validation = false;
                        }
                }

                return validation;
            }
        },
        // 验证表单
        // field 参数不指定时，验证所有控件，指定时只验证指定控件
        validate: function (field) {
            var me = this;
            // 未指定参数
            if (typeof field === 'undefined') {
                var data = {
                    result: true,
                    detail: {}
                };
                var fields = me.getFields();
                for (var name in fields) {
                    var r = me.validate(fields[name]);
                    data.detail[name] = r;
                    if (!r) {
                        // 验证不通过  整体结果为不通过
                        data.result = false;
                    }
                }
                if (typeof me.option.afterValidate === 'function') {
                    setTimeout(function () {
                        me.option.afterValidate.call(me, data.result, data.detail);
                    }, 0);
                }
                return data.result || data.detail;
            }

            // 参数是name名字
            if (typeof field === 'string') {
                field = me.getField(field);
                if (!field.length) {
                    return false;
                }
            }
            if ($.isArray(field)) {
                var val, rule;

                val = me.getData(field);
                rule = me.getRule(field);
                console.log(val, rule)
                if (rule) {
                    var success = rule.expr.test(val);
                    // 更新验证提示
                    var info = field[0];
                    if (success) {
                        info.css('border-color', '#00FF00');
                    } else {
                        info.css('border-color', '#FF0000');
                    }
                    info.show();
                    return success;
                }

                return true;
            }
        },
        // 提交表单
        submit: function (option) {
            option = $.extend({
                url: this.context.attr('action'), // 提交目标utl
                type: this.context.attr('method') || 'post', // 提交类型
                async: true, //是否异步
                data: {}, // 附加参数
                success: false, // 成功回调
                error: false, // 错误回调
                cache: false // 是否缓存
            }, option);

            option.data = $.extend({}, option.data, this.getData());

            $.ajax(option);
        }
    }

    form.prototype.init.prototype = form.prototype;

    $.fn.miniform = function (option) {
        if (this.length > 0) {
            return form(this[0], option);
        }
    }
})(jQuery);